package net.sf.microlog.midp.appender.bluetooth;

import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.UUID;

import net.sf.microlog.core.MicrologConstants;

/**
 * Responsible for the service searches. It is recommended to use the service
 * search if you know the Bluetooth address of the server. This will provide
 * better performance and avoid any issues with hardcoding the channel for the
 * Bluetooth connection.
 * 
 * @author Jarle Hansen (hansjar@gmail.com)
 * @since 2.0
 * 
 */
class BluetoothServiceSearch implements DiscoveryListener {
	private ServiceRecord serviceRecord;

	private boolean serviceSearchCompleted;
	private static final Object lock = new Object();

	private BluetoothServiceSearch() {
	}

	public static BluetoothServiceSearch newInstance() {
		return new BluetoothServiceSearch();
	}

	public String getLoggerServiceString(final BluetoothRemoteDevice remoteDevice) {
		return getConnectionString(remoteDevice, new UUID(MicrologConstants.DEFAULT_BT_UUID_STRING, false));
	}

	/**
	 * By sending in a BluetoothRemoteDevice with a valid Bluetooth address, it
	 * is able to search for the Microlog service. It will return the entire
	 * connection String for the found service. This connection String is then
	 * later used to connect to the server.
	 * 
	 * @param remoteDevice
	 *            The server to connect to, contains a Bluetooth Address
	 * @return
	 */
	private String getConnectionString(final BluetoothRemoteDevice remoteDevice, final UUID uuid) {
		serviceSearchCompleted = false;
		
		try {
			LocalDevice.getLocalDevice().getDiscoveryAgent().searchServices(null, new UUID[] { uuid }, remoteDevice,
					this);

			try {
				synchronized (lock) {
					while (!serviceSearchCompleted) {
						lock.wait();
					}
				}
			} catch (InterruptedException ie) {
			}
		} catch (BluetoothStateException bse) {
			System.err.println("Unable to search for the service on device: " + remoteDevice.getBluetoothAddress()
					+ ", " + bse);
		}

		final String connectionString;

		if (serviceRecord != null) {
			connectionString = serviceRecord.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
		} else {
			connectionString = null;
		}

		return connectionString;
	}

	public void serviceSearchCompleted(final int transactionId, final int responseCode) {
		synchronized (lock) {
			serviceSearchCompleted = true;
			lock.notifyAll();
		}
	}

	/**
	 * TODO what if several Microlog services are detected?
	 */
	public void servicesDiscovered(final int transactionId, final ServiceRecord[] serviceRecords) {
		serviceRecord = serviceRecords[0];
	}

	// Not used in service search
	public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) {
	}

	public void inquiryCompleted(int type) {
	}
}
